package datatableaux;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedList;


import entities.*;
import entities.concept.*;

public class DataBranching {

	private Individual branchInd;
	private LinkedList<Concept> possibleConcepts;
	private LinkedList<Concept> branchConcepts;
	private Concept lastChosenConcept;
	private DataBranchChanges bc;
	private DataBranching fatherBranch;
	
	public DataBranching(Individual ind, HashSet<Concept> cons){
		this.setBranchInd(ind);
		this.possibleConcepts = new LinkedList<Concept>();
		this.possibleConcepts.addAll(cons);
		this.branchConcepts = new LinkedList<Concept>();
		this.branchConcepts.addAll(cons);
		this.fatherBranch  = null;
		bc = new DataBranchChanges();
	}
	
	public LinkedList<Concept> getBranchConcepts() {
		return branchConcepts;
	}
	
	public Individual getBranchingIndividual(){
		return this.getBranchInd();
	}
	public DataBranchChanges getBranchChanges(){
		return this.bc;
	}
	
	public Concept getLastChosenConcept(){
		return this.lastChosenConcept;
	}
	
	public boolean noChoices(){
		return this.possibleConcepts.isEmpty();
	}

	private enum OrSelectStrategies{
		Random, SortedLexiDesc, SortedLexiAsc
	}
	private Concept selectOrConceptStrategy(OrSelectStrategies st){
		switch(st){
		case Random: return this.possibleConcepts.poll(); 
		case SortedLexiDesc: Collections.sort(this.possibleConcepts,
				new Comparator<Concept>(){
					public int compare(Concept c1, Concept c2) {
						return c1.toString().compareTo(c2.toString());
					}
				});
				return this.possibleConcepts.poll();
		case SortedLexiAsc: Collections.sort(this.possibleConcepts,
				new Comparator<Concept>(){
					public int compare(Concept c1, Concept c2) {
						return c2.toString().compareTo(c1.toString());
					}
				});
				return this.possibleConcepts.poll();
		}
		return null;
	}

	public boolean createBranch(){
		if(this.lastChosenConcept != null){
			this.getBranchInd().removeLabels(this.lastChosenConcept);
		}
		if(noChoices()){
			return false;
		}
		Concept c = this.selectOrConceptStrategy(OrSelectStrategies.SortedLexiAsc);
		this.lastChosenConcept = c;
		//start recording all changes now
		DataBranchChanges.setRecordingStatus(true);
		this.getBranchInd().addLabels(c);
		//System.err.println("Or--branch created: "+this.hashCode()+", concept: "+c);
		return true;
	}
	
	//restore the branching ind (record all the changes)
	public void restore(){
		//revert all the changes
		bc.removeLabel();
		bc.removeRelations();
		bc.clearAddedLabels();
		bc.clearAddedRoleRelations();
	}

	public void setBranchInd(Individual branchInd) {
		this.branchInd = branchInd;
	}

	public Individual getBranchInd() {
		return branchInd;
	}
	
	@Override
	public String toString(){
		String s = "";
		s += "ID:"+this.hashCode()+" ["+this.branchInd+"] ["+this.lastChosenConcept+"]";
		return s;
	}


	
	public void setFatherBranch(DataBranching fatherBranch) {
		this.fatherBranch = fatherBranch;
	}

	public DataBranching getFatherBranch() {
		return fatherBranch;
	}
	
}
